home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #19 (Apr 87) / help demo.c / help.c < prev    next >
C/C++ Source or Header  |  1987-03-11  |  15KB  |  542 lines

  1. /************************************************
  2.  * help.c - demo program shows a new way to
  3.  *          present on-line help
  4.  *
  5.  * Bill Rausch, Jan 1987
  6.  * Uses LightSpeed C™ (Think Technologies, Inc.)
  7.  ***********************************************/
  8.  
  9. #include <EventMgr.h>
  10. #include <MenuMgr.h>
  11. #include <WindowMgr.h>
  12. #include <ToolboxUtil.h>
  13. #include <DialogMgr.h>
  14. #include <FontMgr.h>
  15. #include <TextEdit.h>
  16. #include <ListMgr.h>
  17. #include <strings.h>
  18. #include <pascal.h>
  19.  
  20. #define NULL 0L
  21. #define ACTIVATE 0
  22. #define INACTIVATE 255
  23.  
  24. #define FILEID 256
  25. #define ABOUT 1 
  26. #define HELP 2
  27. #define QUIT 3
  28.  
  29. #define HELP_DLG 256
  30. #define HELP_OK 1
  31. #define HELP_BOX 2
  32. #define HELP_LIST 3
  33.  
  34. #define HELP_STR 256 /* STR# containing topics */
  35. #define MAX_HELPS 100 /* application dependent */
  36.  
  37. struct {
  38.   Rect text_box;    /* user item dimensions */
  39.   Rect topic_box;   /* user item dimensions */
  40.   TEHandle text;
  41.   ListHandle topics;
  42.   Rect d_rect;      /* TextEdit's dest rect */
  43.   Rect v_rect;      /* TextEdit's view rect */
  44.   int offset;       /* d_rect vertical shift */
  45.   int lines_vis;    /* number of lines visible */
  46.   ControlHandle text_scroll;
  47.   int max_text;     /* max value of scroller */
  48.   int help_id[MAX_HELPS]; /* topics’ HELP IDs */
  49.   int num_topics;   /* how many topics? */
  50.   int last_one;     /* last cell clicked in */
  51.   } h;
  52.  
  53. pascal Boolean help_filter();
  54. Boolean show_help();
  55. pascal void help_action();
  56.  
  57. /************************************************
  58.  * Trivial main(), just enough to use a single 
  59.  * menu with only three items: About..., Help...,
  60.  * and Quit. No DAs, no windows, no command key
  61.  * equivalents or other key strokes. */
  62. main()
  63.   {
  64.   EventRecord the_event;
  65.   WindowPtr which_window;
  66.   int menu_id, item_number;
  67.   long menu_code;
  68.   int window_code;
  69.   MenuHandle filemenu;
  70.   
  71.   FlushEvents(everyEvent, 0);
  72.   InitGraf(&thePort);
  73.   InitFonts();
  74.   InitWindows();
  75.   InitMenus();
  76.   TEInit();
  77.   InitDialogs(NULL);
  78.   
  79.   filemenu = GetMenu(FILEID);
  80.   InsertMenu(filemenu, 0);
  81.   DrawMenuBar();
  82.   InitCursor();
  83.   
  84.   for (;;)  /* event loop */
  85.     {
  86.     if (GetNextEvent(everyEvent, &the_event)) 
  87.       {
  88.       if (the_event.what == mouseDown)
  89.         {
  90.         window_code = FindWindow(the_event.where,
  91.                                  &which_window);
  92.         if (window_code == inMenuBar)
  93.           {
  94.           menu_code = MenuSelect(the_event.where);
  95.           menu_id = HiWord(menu_code);
  96.           item_number = LoWord(menu_code);
  97.           if (menu_id == FILEID)
  98.             {
  99.             if (item_number == ABOUT)
  100.               do_about(
  101.           "Help demo - Bill Rausch - Jan. 1987",
  102.           "LightSpeed C™ by Think Technologies");
  103.             else if (item_number == HELP)
  104.               do_help(HELP_STR);
  105.             else if (item_number == QUIT)
  106.               ExitToShell();
  107.             else
  108.               SysBeep(1);
  109.             }
  110.           HiliteMenu(0);
  111.           DrawMenuBar();
  112.           }
  113.         else
  114.           SysBeep(1);
  115.         }
  116.       else
  117.         SysBeep(1);
  118.       }
  119.     }
  120.   }
  121.  
  122. /***********************************************/
  123. /* creates alert-like box, waits for mouseDown */
  124. do_about(text1, text2)    
  125. char *text1, *text2;
  126.   {
  127.   long dummy;
  128.   Rect box;
  129.   Rect line;
  130.   GrafPtr old_port;
  131.   WindowPtr window;
  132.   EventRecord an_event;
  133.   
  134.   SetRect(&line, 6, 5, 345, 25);
  135.   SetRect(&box, 75, 125, 425, 180);
  136.   window = NewWindow(NULL, &box, "", TRUE,
  137.                      dBoxProc, -1L, TRUE, NULL);
  138.   GetPort(&old_port);
  139.   SetPort(window);
  140.   
  141.   TextFont(systemFont);
  142.   TextBox(text1, (long)strlen(text1), &line,
  143.           teJustCenter);
  144.   OffsetRect(&line, 0, 28);
  145.   TextBox(text2, (long)strlen(text2), &line,
  146.           teJustCenter);
  147.   
  148.   do { 
  149.     GetNextEvent(everyEvent, &an_event);
  150.     } while (an_event.what != mouseDown);
  151.     
  152.   DisposeWindow(window);
  153.   SetPort(old_port);
  154.   }
  155.  
  156. /************************************************
  157.  * Help routine that makes use of the List 
  158.  * Manager to present user with a list of topics
  159.  * and help text about each one. The topics are
  160.  * stored as a STR# resource and the help texts
  161.  * are stored as HELP resources. Each topic 
  162.  * string contains the number of its associated
  163.  * HELP resource.
  164.  * Note: requires Geneva 10 font to be present */
  165. do_help(str_id)
  166. int str_id;
  167.   {
  168.   DialogPtr the_dialog;
  169.   Handle scr_handle;      /* scratch variable */
  170.   int scratch;            /* scratch variable */
  171.   Str255 scr_str;         /* scratch variable */
  172.   Rect hdata_rect;  /* for list manager setup */
  173.   Point cell_size;  /* for list manager setup */
  174.   Handle topics;    /* for list manager setup */
  175.   int *n_t_ptr;
  176.   GrafPtr old_port;
  177.   
  178.   /* Read STR#, get number topics */
  179.   topics = GetResource('STR#', str_id);
  180.   h.num_topics = *(int *)(*topics);
  181.   
  182.   /* Read dialog box resource */
  183.   the_dialog = GetNewDialog(HELP_DLG, NULL, -1L);
  184.   GetPort(&old_port);    /* save where we were */
  185.   SetPort(the_dialog);
  186.   
  187.   /* get user item for topic list */
  188.   GetDItem(the_dialog, HELP_LIST, &scratch,
  189.            &scr_handle, &h.topic_box);
  190.   InsetRect(&h.topic_box, 1, 1);
  191.   /* leave room for vertical scroll bar */
  192.   h.topic_box.right -= 15;
  193.   SetRect(&hdata_rect, 0, 0, 1, h.num_topics);
  194.   SetPt(&cell_size, h.topic_box.right - 
  195.         h.topic_box.left, 16);
  196.   
  197.   h.topics = LNew(&h.topic_box, &hdata_rect, 
  198.                   cell_size, 0, the_dialog,
  199.                   FALSE, FALSE, FALSE, TRUE);
  200.   (*h.topics)->selFlags = lOnlyOne;
  201.   /* restore rect for framing */
  202.   InsetRect(&h.topic_box, -1, -1);
  203.   read_help(h.topics,h.num_topics,h.help_id,str_id);
  204.                        
  205.   if (!show_help(the_dialog, h.topics, 
  206.                  h.help_id))
  207.     do_about("show_help()",
  208.              "returned an error.");
  209.     
  210.   SetPort(old_port);    /* put us back */
  211.   }
  212.  
  213. /************************************************
  214.  * Read the topics from the STR# resource. Add
  215.  * them to the List as they are read. Also, save
  216.  * the IDs in an array for use later in finding
  217.  * the proper HELP resource to display for each
  218.  * topic. */
  219. read_help(topics, num_topics, help_id, 
  220.                   str_id)
  221. ListHandle topics;
  222. int num_topics;
  223. int help_id[];
  224. int str_id;
  225.   {
  226.   int i;
  227.   Str255 a_topic;
  228.   Point the_cell;
  229.   char *id_number;
  230.   Str255 strvar;
  231.   
  232.   for (i=0; i<num_topics; i++)
  233.     {
  234.     GetIndString(a_topic, str_id, i+1);
  235.     PtoCstr(a_topic);
  236.     id_number = strchr(a_topic, (char)'\\');
  237.     
  238.     /* terminate topic and point to number */
  239.     *id_number++ = '\0';
  240.     help_id[i] = atoi(id_number);
  241.     
  242.     SetPt(&the_cell, 0, i);
  243.     LSetCell(a_topic, strlen(a_topic), the_cell,
  244.              topics);
  245.     }
  246.                
  247.   SetPt(&the_cell, 0, 0);
  248.   LSetSelect((Boolean)TRUE, the_cell, topics);
  249.   LDoDraw((Boolean)TRUE, topics);
  250.   }
  251.  
  252. /************************************************
  253.  * Set up the help text for the first topic in 
  254.  * the list. Call ModalDialog (with a filterProc
  255.  * to do all the work). Loop until user clicks
  256.  * OK. */
  257. Boolean show_help(the_dialog, topics, help_id)
  258. DialogPtr the_dialog;
  259. ListHandle topics;
  260. int help_id[];
  261.   {
  262.   GrafPtr old_port;
  263.   int item_hit;     /* returned by ModalDialog */
  264.   int scr_int;       /* scratch variable */
  265.   Handle scr_handle; /* scratch variable */
  266.   Boolean done = FALSE;
  267.   int i, buf_size;
  268.   Rect scroll_rect;
  269.   Handle the_help;
  270.   
  271.   /* get user item for help text */
  272.   GetDItem(the_dialog, HELP_BOX, &scr_int, 
  273.            &scr_handle, &h.text_box);
  274.   /* leave room for scroll bar */
  275.   h.text_box.right -= 16;
  276.   scroll_rect.right = h.text_box.right + 15;
  277.   scroll_rect.left = h.text_box.right - 1;
  278.   scroll_rect.top = h.text_box.top;
  279.   scroll_rect.bottom = h.text_box.bottom;
  280.   h.text_scroll = NewControl(the_dialog, 
  281.                           &scroll_rect, "", TRUE, 
  282.                           0, 0, 0, 16, NULL);
  283.   HiliteControl(h.text_scroll, INACTIVATE);
  284.   
  285.   /* Set up TextEdit record for the help text */
  286.   h.d_rect.top = h.text_box.top + 1; 
  287.   h.d_rect.left = h.text_box.left + 1;
  288.   h.d_rect.right = h.text_box.right - 1;
  289.   h.d_rect.bottom = 20000;    /* infinity */
  290.   h.v_rect = h.text_box;
  291.   InsetRect(&h.v_rect, 1, 1);
  292.   h.text = TENew(&h.d_rect, &h.v_rect);
  293.   (*h.text)->txFont = geneva;
  294.   (*h.text)->txSize = 10;
  295.   
  296.   h.last_one = 0;    /* 1st topic selected */
  297.   h.offset = 0;      /* at top left corner now */
  298.   h.lines_vis = (h.v_rect.bottom - h.v_rect.top) 
  299.                 / (*h.text)->lineHeight;
  300.   
  301.   /* put 1st topic’s text into help box */
  302.   the_help = GetResource('HELP', help_id[0]);
  303.   buf_size = SizeResource(the_help);
  304.   TEDeactivate(h.text);
  305.   TESetSelect(32767L, 32767L, h.text);
  306.   HLock(the_help);
  307.   TEInsert(*the_help, (long)buf_size, h.text);
  308.   HUnlock(the_help);
  309.   
  310.   /* vertical scroll bar necessary? */
  311.   if ((*h.text)->nLines > h.lines_vis)
  312.     {
  313.     HiliteControl(h.text_scroll, ACTIVATE);
  314.     h.max_text = (((*h.text)->nLines) - 
  315.             h.lines_vis) * (*h.text)->lineHeight;
  316.     SetCtlMax(h.text_scroll, h.max_text); 
  317.     }
  318.  
  319.   ShowWindow(the_dialog);
  320.   do {
  321.     ModalDialog(help_filter, &item_hit);
  322.     if (item_hit == HELP_OK)
  323.       done = TRUE;
  324.     } while (!done);
  325.     
  326.   TEDispose(h.text);
  327.   LDispose(h.topics);
  328.   DisposDialog(the_dialog);
  329.   return TRUE;
  330.   }
  331.  
  332.  
  333. /************************************************
  334.  * This routine handles activating and updating 
  335.  * of the scroller and the box area. We must 
  336.  * handle mouse downs in the scroller and text 
  337.  * box, passing back TRUE, and pass FALSE back 
  338.  * for everything else so the Dialog Manager does
  339.  * his thing on the other items. */
  340. pascal Boolean help_filter(dp, ep, ip)
  341. WindowPtr dp;
  342. EventRecord *ep;
  343. int *ip;
  344.   {
  345.   int part;
  346.   ControlHandle ch;
  347.   char tempchar;  /* check keydown for RETURN */
  348.   Point mouse_loc;
  349.   int start_value, end_value, dummy, delta;
  350.   long a_cell;
  351.   int cell_num;
  352.   Handle the_help;
  353.   int buf_size;
  354.   int scr_int;       /* scratch variable */
  355.   Handle scr_handle; /* scratch variable */
  356.   Rect scr_rect;     /* scratch variable */
  357.   
  358.   switch(ep->what)
  359.     {
  360.     case updateEvt:
  361.       /* is the update event for this window? */
  362.       if (ep->message == (long)dp)
  363.         {
  364.         /* outline default button */
  365.         GetDItem(dp, HELP_OK, &scr_int, 
  366.                  &scr_handle, &scr_rect);
  367.         InsetRect(&scr_rect, -4, -4);
  368.         PenSize(3, 3);
  369.         FrameRoundRect(&scr_rect, 16, 16);
  370.         PenNormal();
  371.         /* draw boxes around topics, text */
  372.         FrameRect(&h.topic_box);
  373.         FrameRect(&h.text_box);
  374.         /* update contents of boxes */
  375.         EraseRect(&h.v_rect);
  376.         TEUpdate(&h.v_rect, h.text);
  377.         LUpdate(dp->visRgn, h.topics);
  378.         }
  379.       return FALSE;
  380.  
  381.     case keyDown: 
  382.       /* convert return key to OK button */
  383.       tempchar = BitAnd(ep->message, 
  384.                         charCodeMask);
  385.       if (tempchar == '\r')
  386.         {
  387.         *ip = HELP_OK;
  388.         return TRUE;
  389.         }
  390.       return FALSE;
  391.       
  392.     case mouseDown:
  393.       /* get our own copy of coordinates */
  394.       mouse_loc = ep->where;
  395.       GlobalToLocal(&mouse_loc);
  396.       
  397.       part = FindControl(mouse_loc, dp, &ch); 
  398.       if (part > 0)
  399.         {
  400.         /* is click in a scroll bar? */
  401.         if (ch == h.text_scroll)
  402.           {
  403.           if (part == inThumb)
  404.             {
  405.             if(TrackControl(ch, mouse_loc, NULL))
  406.               {
  407.               /* reposition help text */
  408.               delta = h.offset - 
  409.                       GetCtlValue(h.text_scroll);
  410.               TEScroll(0, delta, h.text);
  411.               h.offset -= delta;
  412.               }
  413.             }
  414.           else
  415.             TrackControl(ch, mouse_loc, 
  416.                          help_action);
  417.           return TRUE;
  418.           }
  419.         else if (ch == (*h.topics)->vScroll)
  420.           {
  421.           LClick(mouse_loc, ep->modifiers, 
  422.                  h.topics);
  423.           return TRUE;
  424.           }
  425.         else
  426.           return FALSE;
  427.         }
  428.       else if (PtInRect(mouse_loc, *h.topics))
  429.         {
  430.         /* click was in topics list so find which
  431.          * topic was selected and display the
  432.          * proper HELP resource */
  433.         LClick(mouse_loc, ep->modifiers, 
  434.                h.topics);
  435.         a_cell = 0;
  436.         if (LGetSelect(TRUE, &a_cell, h.topics))
  437.           cell_num = HiWord(a_cell);
  438.         if (cell_num >= 0 && 
  439.             cell_num != h.last_one)
  440.           {
  441.           /* get rid of the old text */
  442.           TEDeactivate(h.text);
  443.           TESetSelect(0L, 32767L, h.text);
  444.           TEDelete(h.text);
  445.           if (cell_num < h.num_topics)
  446.             {
  447.             the_help = GetResource('HELP', 
  448.                           h.help_id[cell_num]);
  449.             buf_size = SizeResource(the_help);
  450.             }
  451.           else /* no topic selected so no help */
  452.             buf_size = 0;
  453.           if (buf_size > 0)
  454.             {
  455.             HLock(the_help);
  456.             TEInsert(*the_help, (long)buf_size, 
  457.                      h.text);
  458.             HUnlock(the_help);
  459.             }
  460.           
  461.           /* reset the scroll bar */
  462.           SetCtlValue(h.text_scroll, 0);
  463.           /* reposition the help text */
  464.           delta = h.offset - 
  465.                   GetCtlValue(h.text_scroll);
  466.           TEScroll(0, delta, h.text);
  467.           h.offset -= delta;
  468.           /* scroll bar necessary? */
  469.           if ((*h.text)->nLines > h.lines_vis)
  470.             {
  471.             HiliteControl(h.text_scroll, 
  472.                           ACTIVATE);
  473.             h.max_text = (((*h.text)->nLines) - 
  474.                          h.lines_vis) * 
  475.                          (*h.text)->lineHeight;
  476.             SetCtlMax(h.text_scroll, h.max_text); 
  477.             }
  478.           else
  479.             HiliteControl(h.text_scroll, 
  480.                           INACTIVATE);
  481.           /* finally, save the new topic */
  482.           h.last_one = cell_num;
  483.           }
  484.         return TRUE;
  485.         }
  486.       return FALSE;
  487.   
  488.     default:
  489.       return FALSE;
  490.     }
  491.   } 
  492.  
  493. /************************************************
  494.  * This routine is called by the Toolbox while 
  495.  * executing the TrackControl() routine. It has 
  496.  * to take care of scrolling the text when the 
  497.  * up/down arrow and page parts of the scrollbar 
  498.  * are clicked in. */
  499. pascal void help_action(the_scroll, partcode)
  500. ControlHandle the_scroll;
  501. int partcode;
  502.   {
  503.   int value, delta;
  504.   
  505.   switch (partcode)
  506.     {
  507.     case inUpButton:
  508.       value = GetCtlValue(the_scroll);
  509.       value = (value-(*h.text)->lineHeight > 0)
  510.        ? value-(*h.text)->lineHeight 
  511.        : 0;
  512.       SetCtlValue(the_scroll, value);
  513.       break;
  514.     case inPageUp:  /* move 6 lines at a time */
  515.       value = GetCtlValue(the_scroll);
  516.       value = (value-6*(*h.text)->lineHeight > 0)
  517.        ? value-6*(*h.text)->lineHeight 
  518.        : 0;
  519.       SetCtlValue(the_scroll, value);
  520.       break;
  521.     case inDownButton:
  522.       value = GetCtlValue(the_scroll);
  523.       value = (value + (*h.text)->lineHeight < 
  524.                h.max_text) 
  525.        ? value + (*h.text)->lineHeight 
  526.        : h.max_text;
  527.       SetCtlValue(the_scroll, value);
  528.       break;
  529.     case inPageDown:/* move 6 lines at a time */
  530.       value = GetCtlValue(the_scroll);
  531.       value = (value + 6*(*h.text)->lineHeight < 
  532.               h.max_text) 
  533.        ? value + 6*(*h.text)->lineHeight 
  534.        : h.max_text;
  535.       SetCtlValue(the_scroll, value);
  536.       break;
  537.     }
  538.   
  539.   delta = h.offset - GetCtlValue(h.text_scroll);
  540.   TEScroll(0, delta, h.text);
  541.   h.offset -= delta;
  542.   }